﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel.Description;
using Devtm.ServiceModel.Proxy.Events;
using Devtm.ServiceModel.Helpers;
using System.Collections;
using System.Reflection;

namespace Devtm.ServiceModel.Proxy
{
    
    public class ProxyConfiguration
    {

        private readonly object _lock = new object();
        public Type Interface { get; set; }
        public Type TypeProxy { get; set; }
        private List<IEndpointBehavior> _behaviors;
        private Hashtable _EventOperations = new Hashtable();

        internal ProxyConfiguration()
        {
            _behaviors = new List<IEndpointBehavior>();
        }


        internal T Create<T>()
        {            
            return Create<T>(Resolver);
        }


        internal T Create<T>(IServiceResolver resolver)
        {

            if (resolver == null)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("resolver");

            if (resolver.IsEmpty && !resolver.Refresh())
                throw new Exception("The resolver for interface {0} can't resolve the endpoint");

            var link = resolver.Connector;            

            return Create<T>(link.Parameters());

        }


        /// <summary>
        /// Creates a proxy with the specified parameters
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="p">The p.</param>
        /// <returns></returns>
        internal T Create<T>(object[] p)
        {

            if (TypeProxy == null)
                lock (_lock)
                    if (TypeProxy == null)
                        Factory.CreateWrapper(this);

            T retour = (T)Activator.CreateInstance(TypeProxy, p);

            Client<T> client = retour as Client<T>;
            client.Configuration = this;

            foreach (IEndpointBehavior item in _behaviors)            
                client.AddBehaviors(item);
            
            return retour;

        }

        public ProxyConfiguration Add(params IEndpointBehavior[] behaviors)
        {

            foreach (IEndpointBehavior item in behaviors)
                _behaviors.Add(item);

            return this;

        }


        #region Intercept

        internal EventHandlerOperationName GetEventHandlerOperation(MethodInfo method)
        {

            EventHandlerOperationName e = null;

            string key = method.ToString();

            if (_EventOperations.Contains(key))
                e = _EventOperations[key] as EventHandlerOperationName;
            else
            {
                lock (_lock)
                {
                    if (_EventOperations.Contains(key))
                        e = _EventOperations[key] as EventHandlerOperationName;
                    else

                        _EventOperations.Add(key, e = new EventHandlerOperationName(this));
                }
            }

            return e;

        }

        public EventHandlerOperationName GetEventHandlerOperation(string methodName, params Type[] types)
        {

            EventHandlerOperationName e = null;

            var m = Interface.GetMethod(methodName, types);

            string key = m.ToString();

            if (_EventOperations.Contains(key))
                e = _EventOperations[key] as EventHandlerOperationName;
            else
            {
                lock (_lock)
                {
                    if (_EventOperations.Contains(key))
                        e = _EventOperations[key] as EventHandlerOperationName;
                    else

                        _EventOperations.Add(key, e = new EventHandlerOperationName(this));
                }
            }

            return e;
        }

        #endregion



        public IServiceResolver Resolver { get; set; }

        public ServiceFactory Factory { get; set; }

    }



}
